﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenTK.Graphics.OpenGL;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;

namespace TiverSharp.Service
{
    public class TextureLoader
    {

        public int textureHandler = 0;
        Image<Rgba32> image;
        List<byte> pixels;

        public TextureLoader LoadFromFile(string path)
        {
            //加载贴图
            this.textureHandler = GL.GenTexture();
            GL.BindTexture(TextureTarget.Texture2D, this.textureHandler);
            GL.TextureParameter(this.textureHandler, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
            GL.TextureParameter(this.textureHandler, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);

            GL.TextureParameter(this.textureHandler, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
            GL.TextureParameter(this.textureHandler, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);

            //Load the image
            image = Image.Load<Rgba32>(path);

            //ImageSharp loads from the top-left pixel, whereas OpenGL loads from the bottom-left, causing the texture to be flipped vertically.
            //This will correct that, making the texture display properly.
            image.Mutate(x => x.Flip(FlipMode.Vertical));

            //Convert ImageSharp's format into a byte array, so we can use it with OpenGL.
            pixels = new List<byte>(4 * image.Width * image.Height);
            image.ProcessPixelRows(pixelAccessor =>
            {
                for (int y = 0; y < pixelAccessor.Height; y++)
                {
                    Span<Rgba32> row = pixelAccessor.GetRowSpan(y);

                    // Using row.Length helps JIT to eliminate bounds checks when accessing row[x].
                    for (int x = 0; x < row.Length; x++)
                    {
                        pixels.Add(row[x].R);
                        pixels.Add(row[x].G);
                        pixels.Add(row[x].B);
                        pixels.Add(row[x].A);
                    }
                }
            });
            GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgb, image.Width, image.Height, 0, PixelFormat.Bgra, PixelType.UnsignedByte, pixels.ToArray());
            GL.GenerateMipmap(GenerateMipmapTarget.Texture2D);

            image.Dispose();
            //var image = new Bitmap(path);
            //BitmapData data = image.LockBits(new Rectangle(0, 0, image.Width, image.Height),
            //	ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

            //GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgb, data.Width, data.Height, 0,
            //	OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0);

            //GL.GenerateMipmap(GenerateMipmapTarget.Texture2D);
            //image.UnlockBits(data);
            //image.Dispose();
            return this;
        }
        public TextureLoader(int glHandle)
        {
            this.textureHandler = glHandle;
        }
        public void SetShader(Shader shader)
        {
            shader.SetInt("texture0", 0);

            this.textureHandler = GL.GenTexture();
            // Bind the handle
            GL.ActiveTexture(TextureUnit.Texture0);
            GL.BindTexture(TextureTarget.Texture2D, this.textureHandler);

            GL.TexImage2D(TextureTarget.Texture2D, 0,
             PixelInternalFormat.Rgba, image.Width, image.Height, 0,
             PixelFormat.Rgba, PixelType.UnsignedByte, pixels.ToArray());

            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);

            GL.GenerateMipmap(GenerateMipmapTarget.Texture2D);


        }

        public void Use(TextureUnit unit = TextureUnit.Texture0)
        {
            GL.ActiveTexture(unit);
            GL.BindTexture(TextureTarget.Texture2D, this.textureHandler);
        }
    }
}
